package com.hyt.it.ogt.kq.common.gov.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.hyt.core.util.UUIDUtils;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.common.gov.config.HuaweiCloudObsConfig;
import com.obs.services.ObsClient;
import com.obs.services.model.DeleteObjectResult;
import com.obs.services.model.DeleteObjectsRequest;
import com.obs.services.model.DeleteObjectsResult;
import com.obs.services.model.HttpMethodEnum;
import com.obs.services.model.ListVersionsRequest;
import com.obs.services.model.ListVersionsResult;
import com.obs.services.model.ObjectMetadata;
import com.obs.services.model.ObsObject;
import com.obs.services.model.PutObjectResult;
import com.obs.services.model.TemporarySignatureRequest;
import com.obs.services.model.TemporarySignatureResponse;
import com.obs.services.model.VersionOrDeleteMarker;

import lombok.extern.slf4j.Slf4j;

/**
 * @author huangyh
 */
@Slf4j
@Component
public class HuaweiCloudObsUtil {

    /**
     * 华为云OBS配置
     */
    private static HuaweiCloudObsConfig obsConfig;

    /**
     * OBS客户端
     */
    private static ObsClient obsClient;


    @Autowired
    public void setConfig(HuaweiCloudObsConfig huaweiCloudObsConfig) {
        //注入配置
        obsConfig = huaweiCloudObsConfig;
    }

    @PostConstruct
    public void init() {
        //初始化OBS客户端
        obsClient = new ObsClient(obsConfig.getAccessKey(), obsConfig.getSecretKey(), obsConfig.getEndPoint());
    }



    /**
     * 获取对象访问路径
     * @param objectName
     * @return
     */
    public static String getObjectUrl(String objectName){
        //对象访问路径为：https://桶名.域名/对象名
        return StringUtils.join("https://", obsConfig.getBucket(), "." , obsConfig.getEndPoint(), "/" , objectName);
    }



    /**
     * 通过输入流的方式上传文件，指定文件名，并返回文件路径
     * @param name 文件名
     * @param inputStream 流
     * @return 文件路径
     */
    public static String uploadFile(String name, InputStream inputStream) throws KqException {
        PutObjectResult putObjectResult = obsClient.putObject(obsConfig.getBucket(), name, inputStream);
        int statusCode = putObjectResult.getStatusCode();
        if (statusCode != HttpServletResponse.SC_OK) {
            throw new KqException(statusCode, "华为云OBS文件上传异常");
        }
        return putObjectResult.getObjectUrl();
    }

    public static String uploadFileTest(String name, InputStream inputStream) throws KqException {
        PutObjectResult putObjectResult = obsClient.putObject(obsConfig.getBucket(), name, inputStream);
        int statusCode = putObjectResult.getStatusCode();
        if (statusCode != HttpServletResponse.SC_OK) {
            throw new KqException(statusCode, "华为云OBS文件上传异常");
        }
        return putObjectResult.getObjectUrl();
    }

    /**
     * 通过输入流的方式上传文件，随机生成文件名，并返回文件路径
     * @param inputStream 流
     * @return 文件路径
     */
    public static String uploadFile(InputStream inputStream) throws KqException {
        PutObjectResult putObjectResult = obsClient.putObject(obsConfig.getBucket(), UUIDUtils.newSortUUID(), inputStream);
        int statusCode = putObjectResult.getStatusCode();
        if (statusCode != HttpServletResponse.SC_OK) {
            throw new KqException(statusCode, "华为云OBS文件上传异常");
        }
        return putObjectResult.getObjectUrl();
    }

    /**
     * 通过输入流的方式上传文件，指定文件名，并返回文件结果对象
     * @param name 文件名
     * @param inputStream 流
     * @return 上传文件结果对象
     */
    public static PutObjectResult uploadFileResult(String name, InputStream inputStream) throws KqException {
        PutObjectResult putObjectResult = obsClient.putObject(obsConfig.getBucket(), name, inputStream);
        int statusCode = putObjectResult.getStatusCode();
        if (statusCode != HttpServletResponse.SC_OK) {
            throw new KqException(statusCode, "华为云OBS文件上传异常");
        }
        return putObjectResult;
    }

    /**
     * 通过输入流的方式上传文件，随机生成文件名，并返回文件结果对象
     * @param inputStream 流
     * @return 上传文件结果对象
     */
    public static PutObjectResult uploadFileResult(InputStream inputStream) throws KqException {
        PutObjectResult putObjectResult = obsClient.putObject(obsConfig.getBucket(), UUIDUtils.newSortUUID(), inputStream);
        int statusCode = putObjectResult.getStatusCode();
        if (statusCode != HttpServletResponse.SC_OK) {
            throw new KqException(statusCode, "华为云OBS文件上传异常");
        }
        return putObjectResult;
    }

    /**
     * 根据文件名下载文件并生成临时文件
     * @param name 文件名
     * @return 临时问价对象
     * @throws IOException IO异常
     */
    public static File downFile(String name) throws IOException {
        //获取OBS对象
        ObsObject obsObject = obsClient.getObject(obsConfig.getBucket(), name);
        //获取文件流
        InputStream inputStream = obsObject.getObjectContent();
        //获取文件后缀
        String suffix = name.substring(name.lastIndexOf('.') - 1);
        //创建临时文件
        File file = File.createTempFile("temp_", suffix);
        //写入临时文件
        OutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(file);
            int len;
            byte[] buffer = new byte[8192];
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
        } finally {
            if (outputStream != null) {
                outputStream.close();
            }
            inputStream.close();
        }
        return file;
    }

    /**
     * 根据文件名获取流（ObsObject.getObjectContent获取的对象输入流一定要显式关闭，否则会造成资源泄露）
     * @param name 文件名
     * @return 流
     */
    public static InputStream getInputStream(String name) {
        ObsObject obsObject = obsClient.getObject(obsConfig.getBucket(), name);
        return obsObject.getObjectContent();
    }

    /**
     * 根据文件名删除文件
     * @param name 文件名
     * @return 删除文件结果对象
     */
    public static DeleteObjectResult deleteFile(String name) throws KqException {
        return deleteFile(name, false);
    }

    /**
     * 根据文件名删除文件，指定是否抛出异常
     * @param name 文件名
     * @param throwException 是否抛出异常
     * @return 删除文件结果对象
     * @throws KqException 文件删除异常
     */
    public static DeleteObjectResult deleteFile(String name, boolean throwException) throws KqException {
        DeleteObjectResult deleteObjectResult = obsClient.deleteObject(obsConfig.getBucket(), name);
        int statusCode = deleteObjectResult.getStatusCode();
        if (statusCode != HttpServletResponse.SC_OK) {
            if (throwException) {
                throw new KqException(statusCode, "华为云OBS文件删除异常");
            }
        }
        return deleteObjectResult;
    }

    /**
     * 批量删除桶内所有对象
     * @param bucketName 桶名
     */
    public static void deleteBatch(String bucketName) {
        ListVersionsRequest request = new ListVersionsRequest(bucketName);
        //每次最多删除1000个对象
        request.setMaxKeys(1000);
        ListVersionsResult result;
        do {
            result = obsClient.listVersions(request);
            DeleteObjectsRequest deleteRequest = new DeleteObjectsRequest(bucketName);
            for (VersionOrDeleteMarker v  : result.getVersions()) {
                deleteRequest.addKeyAndVersion(v.getKey(), v.getVersionId());
            }
            DeleteObjectsResult deleteResult = obsClient.deleteObjects(deleteRequest);
            //获取删除成功的对象
            List<DeleteObjectsResult.DeleteObjectResult> success = deleteResult.getDeletedObjectResults();
            //获取删除失败的对象
            List<DeleteObjectsResult.ErrorResult> fail = deleteResult.getErrorResults();
            request.setKeyMarker(result.getNextKeyMarker());
            request.setVersionIdMarker(result.getNextVersionIdMarker());
        } while (result.isTruncated());
    }

    /**
     * 根据名称获取对象属性
     * @param name 名称
     * @return 对象属性
     */
    public static ObjectMetadata getObjectMetadata(String name) {
        return obsClient.getObjectMetadata(obsConfig.getBucket(), name);
    }

    /**
     * 获取临时url
     * @param name 名称
     * @return 临时url
     */
    public static String getTemporaryUrl(String name) {
        TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, obsConfig.getExpireSeconds());
        request.setBucketName(obsConfig.getBucket());
        request.setObjectKey(name);
        TemporarySignatureResponse response = obsClient.createTemporarySignature(request);
        return response.getSignedUrl();
    }

}
